package com.kla.power.util;

import com.alibaba.fastjson.JSONArray;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Author: Wuzh
 * @Description: 工具类
 * @Date Created in 13:46 2020/9/10
 * @return
 */
public class CommonUtil {


    public static final SimpleDateFormat sdf = new SimpleDateFormat ( "yyyyMMdd" );


    public static String getCurrentSimpleDate () {
        return sdf.format ( Calendar.getInstance ().getTime () );
    }


    public static Date getCurrDate (int isMin) {
        SimpleDateFormat sdFormat = null;
        if ( isMin == 1 ) {
            sdFormat = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss SSS" );
        } else {
            sdFormat = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" );
        }
        Date date = new Date ();
        String dateString = sdFormat.format ( date );
        ParsePosition pos = new ParsePosition ( 0 );
        Date currentTime_2 = sdFormat.parse ( dateString, pos );
        return currentTime_2;
    }

    /**
     * 将时间转化成指定格式-Date-String
     * @param date
     * @param format
     * @return String
     */
    public static String getDateStrFormat (Date date, String format) {
        String reString = "";
        try {
            SimpleDateFormat sdFormat = new SimpleDateFormat ( format );
            //Date date = sdFormat.parse(orDate);
            reString = sdFormat.format ( date );
        } catch ( Exception e ) {
            // TODO: handle exception
        }
        return reString;
    }


    /**
     * 通过整数月份解析字符串两位月份
     * @param month
     * @return
     */
    public static String parseMonthByDecimal (int month) {
        String strMonth = "";
        switch ( month ) {
            case 1:
                strMonth = "01";
                break;
            case 2:
                strMonth = "02";
                break;
            case 3:
                strMonth = "03";
                break;
            case 4:
                strMonth = "04";
                break;
            case 5:
                strMonth = "05";
                break;
            case 6:
                strMonth = "06";
                break;
            case 7:
                strMonth = "07";
                break;
            case 8:
                strMonth = "08";
                break;
            case 9:
                strMonth = "09";
                break;
            case 10:
                strMonth = "10";
                break;
            case 11:
                strMonth = "11";
                break;
            case 12:
                strMonth = "12";
                break;
        }
        return strMonth;
    }

    /**
     * @return
     * @Author: Wuzh
     * @Description: 获取系统当前格式化时间
     */
    public static String getFormatDateTime (String format) {
        LocalDateTime localDateTime = LocalDateTime.now ();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern ( format );
        return dateTimeFormatter.format ( localDateTime );
    }


    /**
     * LocalDate转Date
     * @param localDateTime
     * @return
     */
    public static Date format (LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault ();
        ZonedDateTime zdt = localDateTime.atZone ( zoneId );
        Date date = Date.from ( zdt.toInstant () );
        return date;
    }

    /**
     * Date转LocalDateTime
     * @param date
     * @return
     */
    public static LocalDateTime parseToDate (Date date) {
        ZoneId zoneId = ZoneId.systemDefault ();
        LocalDateTime localDateTime = LocalDateTime.ofInstant ( date.toInstant (), zoneId );
        return localDateTime;
    }


    /**
     * 将六位整数表示的年月日时分秒转成Date日期格式
     * @param year
     * @param month
     * @param day
     * @param hour
     * @param min
     * @param sec
     * @return
     */
    public static Date intToDate (int year, int month, int day, int hour, int min, int sec) {
        Calendar calendar = Calendar.getInstance ();
        calendar.set ( Calendar.YEAR, year );
        calendar.set ( Calendar.MONTH, ( month - 1 ) );
        calendar.set ( Calendar.DAY_OF_MONTH, day );
        calendar.set ( Calendar.HOUR_OF_DAY, hour );
        calendar.set ( Calendar.MINUTE, min );
        calendar.set ( Calendar.SECOND, sec );
        return calendar.getTime ();
    }


    /**
     * 检查是否为同一天
     * @param month
     * @return
     */
    public static boolean checkDay (String month) {
        LocalDate localDate = LocalDate.now ();
        String monthValue = localDate.getMonthValue () < 10 ? ( "0" + localDate.getMonthValue () ) : localDate.getMonthValue () + "";
        String dayValue = localDate.getDayOfMonth () < 10 ? ( "0" + localDate.getDayOfMonth () ) : localDate.getDayOfMonth () + "";
        String yearAndMonth = localDate.getYear () + "-" + monthValue + "-" + dayValue;
        if ( month.equals ( yearAndMonth ) ) {
            return true;
        }
        return false;
    }

    /**
     * 检查给定的年月是否为当前月份
     * @param month
     * @return
     */
    public static boolean checkMonth (String month) {
        LocalDate localDate = LocalDate.now ();
        String monthValue = localDate.getMonthValue () < 10 ? ( "0" + localDate.getMonthValue () ) : localDate.getMonthValue () + "";
        String yearAndMonth = localDate.getYear () + "-" + monthValue;
        if ( month.equals ( yearAndMonth ) ) {
            return true;
        }
        return false;
    }

    /**
     * 检查给定的年是否为今年
     * @param year
     * @return
     */
    public static boolean checkYear (String year) {
        LocalDate localDate = LocalDate.now ();
        String yearAndMonth = localDate.getYear () + "";
        if ( year.equals ( yearAndMonth ) ) {
            return true;
        }
        return false;
    }

    /**
     * 获得当前年月
     * @return
     */
    public static String parseMonth () {
        LocalDate localDate = LocalDate.now ();
        String monthValue = localDate.getMonthValue () < 10 ? ( "0" + localDate.getMonthValue () ) : localDate.getMonthValue () + "";
        String yearAndMonth = localDate.getYear () + "-" + monthValue;
        return yearAndMonth;
    }

    /**
     * 获取给定长度的随机整数
     * @param length 长度
     * @return
     */
    public static String getInviteCode (int length) {
        StringBuilder sb = new StringBuilder ();
        Random random = new Random ();
        char arrays[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
        for ( int i = 0; i < length; i++ ) {
            sb.append ( arrays[random.nextInt ( arrays.length )] );
        }
        return sb.toString ();
    }


    /**
     * 获取给定长度的整数随机数
     * @param length 长度
     * @return
     */
    public static String getRandom (int length) {
        StringBuilder sb = new StringBuilder ();
        Random random = new Random ();
        int arrays[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        for ( int i = 0; i < length; i++ ) {
            sb.append ( arrays[random.nextInt ( arrays.length )] );
        }
        return sb.toString ();
    }


    /**
     * 求两个字符串格式的数值之和
     * @param add1
     * @param add2
     * @return
     */
    public static String sum (String add1, String add2) {
        if ( StringUtils.isBlank ( add1 ) || StringUtils.isBlank ( add2 ) ) {
            return "0.0";
        }
        double dAdd1 = Double.valueOf ( add1 );
        double dAdd2 = Double.valueOf ( add2 );
        String res = String.valueOf ( dAdd1 + dAdd2 );
        String substring = res.substring ( res.lastIndexOf ( "." ) );
        String result = "";
        if ( substring.length () > 2 ) {
            DecimalFormat decimalFormat = new DecimalFormat ( "0.00" );//构造方法的字符格式这里如果小数不足2位,会以0补足.String
            result = decimalFormat.format ( dAdd1 + dAdd2 );//format 返回的是字符串
        } else {
            result = String.valueOf ( dAdd1 + dAdd2 );
        }
        return result;
    }

    /**
     * 求两个小数之和并保留两位小数
     * @param dAdd2
     * @param dAdd2
     * @return
     */
    public static double sum (double dAdd1, double dAdd2) {
        DecimalFormat df = new DecimalFormat ( "#.00" );
        double sum = dAdd1 + dAdd2;
        return Double.valueOf ( df.format ( sum ) );
    }

    /**
     * 计算两个字符串类型的小数乘积，当结果小数位大于2时，保留2位；当结果小数位小于2时，保留原来的
     * @param multiplier
     * @param multiplicand
     * @return
     */
    public static String ride (String multiplier, String multiplicand) {
        if ( StringUtils.isBlank ( multiplier ) || StringUtils.isBlank ( multiplicand ) ) {
            return "0.0";
        }
        double dMultiplier = Double.valueOf ( multiplier );
        double dMultiplicand = Double.valueOf ( multiplicand );
        String res = String.valueOf ( dMultiplier * dMultiplicand );
        String substring = res.substring ( res.lastIndexOf ( "." ), res.length () );
        String result = "";
        if ( substring.length () > 2 ) {
            DecimalFormat decimalFormat = new DecimalFormat ( "0.00" );//构造方法的字符格式这里如果小数不足2位,会以0补足.String
            result = decimalFormat.format ( dMultiplier * dMultiplicand );//format 返回的是字符串
        } else {
            result = String.valueOf ( dMultiplier * dMultiplicand );
        }
        return result;
    }

    /**
     * 计算两个小数除法，当结果小数位大于2时，保留2位；当结果小数位小于2时，保留原来的
     * @param divisor
     * @param dividend
     * @return
     */
    public static String divided (double divisor, double dividend) {
        if ( divisor == 0 || dividend == 0 ) {
            return "0.0";
        }
        String res = String.valueOf ( divisor / dividend );
        String substring = res.substring ( res.lastIndexOf ( "." ) );
        String result = "";
        if ( substring.length () > 2 ) {
            DecimalFormat decimalFormat = new DecimalFormat ( "0.00" );//构造方法的字符格式这里如果小数不足2位,会以0补足.String
            result = decimalFormat.format ( divisor / dividend );//format 返回的是字符串
        } else {
            result = String.valueOf ( divisor / dividend );
        }
        return result;
    }

    /**
     * 将一个double数据缩小多少倍，并保留几位小数
     * @param number
     * @param multiple
     * @param pointer
     * @return
     */
    public static String reduce (double number, int multiple, int pointer) {
        if ( number == 0 || multiple == 0 ) {
            return "0.0";
        }
        number = number / multiple;
        String strNumber = String.format ( "%." + pointer + "f", number );
        return strNumber;
    }


    /**
     * 将整数缩小固定倍数，并保留三位小数点
     * @param value    十进制整数
     * @param multiple 缩小的倍数
     * @param pointer  保留的小数点
     * @return
     */
    public static String parseDecimalPoint (int value, int multiple, int pointer) {
        if ( value == 0 || value == 0 ) {
            return "0.0";
        }
        if ( value < 0 ) {
            // 负数
            value = - value;
            double v = 1.0 * value / multiple;
            String strNumber = String.format ( "%." + pointer + "f", v );
            return "-".concat ( strNumber );
        }
        double v = 1.0 * value / multiple;
        String strNumber = String.format ( "%." + pointer + "f", v );
        return strNumber;
    }

    /**
     * 将double小数保留两个小数点并返回
     * @param value
     * @return
     */
    public static String parseDecimalPoint (double value) {
        String substring = String.valueOf ( value );
        String result = "";
        if ( substring.length () > 2 ) {
            DecimalFormat decimalFormat = new DecimalFormat ( "0.00" );
            result = decimalFormat.format ( value );//format 返回的是字符串
        } else {
            result = String.valueOf ( value );
        }
        return result;
    }

    /**
     * 整数数组转成缩小10倍转成小数
     * @param array
     * @return
     */
    public static String arrayToReduceString (int[] array) {
        if ( array == null || array.length == 0 ) {
            return "0.0";
        }
        StringBuilder stringBuilder = new StringBuilder ();
        for ( int i : array ) {
            if ( i != 0 ) {
                stringBuilder.append ( i );
            }
        }
        if ( "".equals ( stringBuilder ) || stringBuilder.length () == 0 ) {
            return "0.0";
        }
        double r = 1.0 * Double.parseDouble ( stringBuilder.toString () ) / 10;
        return String.valueOf ( r );
    }

    /**
     * 十进制整数转换成字节短整型
     * @param value
     * @return
     */
    public static short decimalToShort (int value) {
        return (short) value;
    }

    /**
     * 整数数组转成字符串
     * @param array
     * @return
     */
    public static String arrayToString (int[] array) {
        if ( array == null || array.length == 0 ) {
            return "0";
        }
        StringBuilder stringBuilder = new StringBuilder ();
        for ( int i : array ) {
            if ( i != 0 ) {
                stringBuilder.append ( i );
            }
        }
        return stringBuilder.toString ();
    }

    /**
     * 整数数组转十六位二进制
     * @return
     */
    public static String arrayToBinary (int[] array) {
        if ( array == null || array.length == 0 ) {
            return "-1";
        }
        StringBuilder stringBuilder = new StringBuilder ();
        for ( int i : array ) {
            stringBuilder.append ( i );
        }
        if ( "".equals ( stringBuilder.toString () ) ) {
            return "-1";
        }
        String binary = Integer.toBinaryString ( Integer.parseInt ( stringBuilder.toString () ) );
        int length = binary.length ();
        for ( int i = 0; i < ( 16 - length ); i++ ) {
            binary = "0".concat ( binary );
        }
        return binary;
    }

    /**
     * 整数数组转16位二进制
     * @return
     */
    public static String decimalTo16Binary (int data) {
        if ( data == 0 ) {
            return "0000000000000000";
        }
        String binary = Integer.toBinaryString ( data );
        int length = binary.length ();
        for ( int i = 0; i < ( 16 - length ); i++ ) {
            binary = "0".concat ( binary );
        }
        return binary;
    }


    /**
     * 整数数组转32位二进制
     * @return
     */
    public static String decimalToBinary (int data) {
        if ( data == 0 ) {
            return "0";
        }
        String binary = Integer.toBinaryString ( data );
        int length = binary.length ();
        for ( int i = 0; i < ( 32 - length ); i++ ) {
            binary = "0".concat ( binary );
        }
        return binary;
    }


    /**
     * 数组解析为十进制整数
     * @param arr
     * @return
     */
    public static String parseInt (int[] arr) {
        StringBuilder stringBuilder = new StringBuilder ();
        for ( int i : arr ) {
            stringBuilder.append ( i );
        }
        return stringBuilder.toString ();
    }

    /**
     * 今天所在的一周7天日期
     * @param myDate
     * @return
     */
    public static List<Date> dateToCurrentWeek (Date myDate) {
        Calendar cal = Calendar.getInstance ();
        cal.setTime ( myDate );
        int b = cal.get ( Calendar.DAY_OF_WEEK ) - 1;
        if ( b == 0 ) {
            b = 7;
        }
        Date fdate;
        List<Date> list = new ArrayList<Date> ();
        Long fTime = myDate.getTime () - b * 24 * 3600000;
        for ( int a = 1; a <= 7; a++ ) {
            fdate = new Date ();
            fdate.setTime ( fTime + ( a * 24 * 3600000 ) );
            list.add ( a - 1, fdate );
        }
        return list;
    }


    /**
     * 判断两个Date类型的日期是否为同一天，比较其中的年月日即可
     * @param date1
     * @param date2
     * @return
     */
    public static boolean checkSameDate (Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance ();
        calendar1.setTime ( date1 );
        Calendar calendar2 = Calendar.getInstance ();
        calendar2.setTime ( date2 );
        // 比较日期是否相同
        if ( calendar1.get ( Calendar.YEAR ) == calendar2.get ( Calendar.YEAR )
                && calendar1.get ( Calendar.MONTH ) == calendar2.get ( Calendar.MONTH )
                && calendar1.get ( Calendar.DAY_OF_MONTH ) == calendar2.get ( Calendar.DAY_OF_MONTH ) ) {
            return true;
        }
        return false;
    }


    /**
     * 判断字符串集合里每个字符串是否都是0
     * 如果是0，则返回false
     * @param data
     * @return：当全部都是0时，返回false；如果存在任意一个不为0的元素时，返回true
     */
    public static boolean checkEmpty (List<String> data) {
        for ( String datum : data ) {
            if ( datum != null && ! "0".equals ( datum ) ) {
                return true;
            }
        }
        return false;
    }


    /**
     * 生成token
     * @return
     */
    public static String getToken () {
        return UUID.randomUUID ().toString ();
    }


    public static void main (String[] args) {
        String s = MD5Util ( "123qwe!@#" );
        System.out.println ( s );
    }

    /***
     * MD5加密（生成唯一的MD5值）
     * @param key
     * @return
     * @throws Exception
     */
    public static String MD5Util (String key) {
        /*
         * 加密需要使用JDK中提供的类
         */
        StringBuffer sb = new StringBuffer ();
        try {
            MessageDigest digest = MessageDigest.getInstance ( "MD5" );
            byte[] bs = digest.digest ( key.getBytes () );
            /*
             *  加密后的数据是-128 到
             *  127 之间的数字，这个数字也不安全。
             *   取出每个数组的某些二进制位进行某些运算，得到一个具体的加密结果
             *   0000 0011 0000 0100 0010 0000 0110 0001
             *  &0000 0000 0000 0000 0000 0000 1111 1111
             *  ---------------------------------------------
             *   0000 0000 0000 0000 0000 0000 0110 0001
             *   把取出的数据转成十六进制数
             */
            for ( byte b : bs ) {
                int x = b & 255;
                String s = Integer.toHexString ( x );
                if ( x > 0 && x < 16 ) {
                    sb.append ( "0" );
                    sb.append ( s );
                } else {
                    sb.append ( s );
                }
            }
        } catch ( Exception e ) {
            System.out.println ( "加密失败" );
        }
        return sb.toString ();
    }

    /**
     * 时间戳转Date
     * @param timeStamp
     * @return
     */
    public static Date parseTimeStamp (long timeStamp) {
        Date date = new Date ( timeStamp );
        return date;
    }

    /**
     * JSON数组转集合
     * @param jsonArray
     * @return
     */
    public static List<String> parseArray (JSONArray jsonArray) {
        List<String> list = new ArrayList<> ();
        for ( int i = 0; i < jsonArray.size (); i++ ) {
            if ( jsonArray.getString ( i ) != null && ! "null".equals ( jsonArray.getString ( i ) ) ) {
                list.add ( String.valueOf ( jsonArray.get ( i ) ) );
            } else {
                list.add ( "0" );
            }
        }
        return list;
    }


    /**
     * 计算两个时间差（h）
     * @param startDate
     * @param endDate
     * @return
     */
    public static Double timeDifference (Date startDate, Date endDate) {
        if ( startDate == null || endDate == null ) {
            return 0.0;
        }
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime () - startDate.getTime ();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        long sec = diff % nd % nh % nm / ns;
        // 计算为以小时为单位的小数时间
        double timeout = 0;
        if ( day > 0 ) {
            timeout += ( day * 24 );
        }
        if ( hour > 0 ) {
            timeout += hour;
        }
        if ( min > 0 ) {
            timeout += ( 1.0 * min / 60 );
        }
        timeout += ( 1.0 * sec / 3600 );
        BigDecimal two11 = new BigDecimal ( timeout );
        timeout = two11.setScale ( 2, BigDecimal.ROUND_HALF_UP ).doubleValue ();
        return timeout;
    }


    /**
     * 汉字转拼音
     * @param chinese
     * @return
     */
    public String changeSpell (String chinese) {
        //将汉字参数去除空格后转化为数组
        char[] chineseArr = chinese.trim ().toCharArray ();
        //定义一个字符串
        StringBuilder spell = new StringBuilder ();
        //输出格式
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat ();
        /**
         * 输出大小写设置
         * LOWERCASE:输出小写
         * UPPERCASE:输出大写
         */
        format.setCaseType ( HanyuPinyinCaseType.LOWERCASE );
        /**
         * 输出音标设置
         * WITH_TONE_MARK:直接用音标符（必须设置WITH_U_UNICODE，否则会抛出异常）
         * WITH_TONE_NUMBER：1-4数字表示音标
         * WITHOUT_TONE：没有音标
         */
        format.setToneType ( HanyuPinyinToneType.WITHOUT_TONE );
        /**
         * 特殊音标ü设置
         * WITH_V：用v表示ü
         * WITH_U_AND_COLON：用"u:"表示ü
         * WITH_U_UNICODE：直接用ü
         */
        format.setVCharType ( HanyuPinyinVCharType.WITH_U_UNICODE );

        try {
            for ( int i = 0; i < chineseArr.length; i++ ) {
                //判断是否是汉字
                if ( Character.toString ( chineseArr[i] ).matches ( "[\\u4E00-\\u9FA5]+" ) ) {
                    //如果是多音字，返回多个拼音的数组
                    String[] pys = PinyinHelper.toHanyuPinyinStringArray ( chineseArr[i], format );
                    //只取数组中的第一个
                    spell.append ( pys[0] );
                } else {
                    //如果不是汉字直接拼接到spell中
                    spell.append ( chineseArr[i] );
                }
            }
        } catch ( BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination ) {
            badHanyuPinyinOutputFormatCombination.printStackTrace ();
        }
        return spell.toString ().toUpperCase ();
    }
}
